﻿using System;
using System.Configuration;
using System.Reflection;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;

namespace API.Helpers
{
    //TODO: Needs some code review aka some butchering :)
    public static class DependencyInjectionHelper
    {
        public static IDependencyInjectionResolver DependencyInjectionResolver { get; set; }

        static DependencyInjectionHelper()
        {
            DependencyInjectionResolver = new UnityDependencyInjectionResolver();
        }

        public static void RegisterType<T, TC>()
            where T : class
            where TC : class
        {
            DependencyInjectionResolver.RegisterType<T, TC>();
        }

        public static T Resolve<T>()
            where T : class
        {
            return DependencyInjectionResolver.Resolve<T>();
        }

        public static T Resolve<T>(Type typeIfNotFound)
            where T : class
        {
            return DependencyInjectionResolver.Resolve<T>(typeIfNotFound);
        }
    }

    public interface IDependencyInjectionResolver
    {
        void RegisterType<T, TC>()
            where T : class
            where TC : class;
        T Resolve<T>()
            where T : class;
        T Resolve<T>(Type typeIfNotFound)
            where T : class;
    }

    public class UnityDependencyInjectionResolver : IDependencyInjectionResolver
    {
        public void RegisterType<T, TC>()
            where T : class
            where TC : class
        {
            UnityHelper.Instance.RegisterType(typeof(T), typeof(TC));
        }

        public T Resolve<T>()
            where T : class
        {
            return Resolve<T>(null);
        }

        public T Resolve<T>(Type typeIfNotFound)
            where T : class
        {
            try
            {
                return UnityHelper.Instance.Resolve<T>();
            }
            catch (Exception)
            {
                var resolvedType = Type.GetType(typeof(T).FullName.Replace(".I", "."));
                if (resolvedType == null)
                    resolvedType = typeof(T).Assembly.GetType(typeof(T).FullName.Replace(".I", "."));
                if (resolvedType != null)
                    return (T)Activator.CreateInstance(resolvedType);
                if (typeIfNotFound != null)
                    return (T)Activator.CreateInstance(typeIfNotFound);
                return default(T);
            }
        }
    }

    internal static class UnityHelper
    {
        private const string UnityConfigSectionId = "unity";
        private static readonly object Lock = new object();
        private static volatile UnityContainer _instance;

        public static UnityContainer Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (Lock)
                    {
                        if (_instance == null)
                        {
                            _instance = new UnityContainer();
                            var unityConfigSection
                              = (UnityConfigurationSection)ConfigurationManager.GetSection(UnityConfigSectionId);
                            if (unityConfigSection != null)
                                unityConfigSection.Configure(_instance);
                        }
                    }
                }
                return _instance;
            }
        }

    }
}